/**
  Szybkie operacje na listach postingowych
  wersja z rankingiem
*/
#include <stdio.h>
#include <math.h>
#include<Python.h>
#undef assert
#define assert(X) {if(!(X)){printf("assertion failed on line %d\n >>%s\n", __LINE__, #X);++*((int*)(NULL));}}

long ** links;
int* len;
int* score;
int* jumpTo;
int lenJumpTo;
int totalNumber;
int modulo = 1000;

long teleport(){
    int ans = jumpTo[ rand() % lenJumpTo];
    if( ans >= totalNumber || ans < 0)
    {
        printf(".");
        return teleport();
    }    
    return ans;
}

long nextNode(long node){
    
    if( len[node] == 0 ){
        return teleport();
    }
    else{
        if(rand() % modulo == 1)
            return teleport();
        else{
            int r = rand() % len[node];
            long ans = links[node][ r ];    
            if( ans >= totalNumber || ans < 0)
            {
                printf("iteruj.c l28 %ld %ld %d %d\n", node, ans, len[node], r);
                int i;
                for( i = 0 ; i < len[node]; i ++)
                {
                    printf("%ld\n",links[node][i] );
                }
                exit(1);
            }
            return ans;
       }
    }
}

static PyObject* putLinks(PyObject* self, PyObject* args)
{
    PyObject * o1;
    int number;
    if (!PyArg_ParseTuple(args, "Oi", &o1, &number) )
        return NULL;
    
    int len1 = (int) PyList_Size( o1 );
    
    links[number] = malloc(len1 * sizeof(int) );
    len[number] = len1;

    int i;
    for( i = 0 ; i < len1 ; i++)
    {
        links[number][i] =  PyLong_AsLong( PyList_GET_ITEM(o1, i) ) ;
        if( links[number][i]  < 0 || links[number][i] >= totalNumber){
            printf("iteruj.c l52 %ld\n",links[number][i]);
            exit(1);
        }
    }
    
   return Py_BuildValue("i",  0 ) ;     
}

static PyObject* _initIter(PyObject* self, PyObject* args)
{
    int number;
    if (!PyArg_ParseTuple(args, "i", &number) )
        return NULL;            
    totalNumber = number;
    links = malloc( number * sizeof(int *) );
    len = malloc(number * sizeof(int) );
    score = malloc(number * sizeof(int) );
    jumpTo = malloc(number * sizeof(int) );
    lenJumpTo = number;
    int i;
    
    for(i = 0 ; i < number ; i++){
        len[i] = 0;
       jumpTo[i] = i;
    }
    return Py_BuildValue("i",  0 );
}

static PyObject* setJump(PyObject* self, PyObject* args)
{
    int l1,l2,l3,l4;
    if (!PyArg_ParseTuple(args, "(iiii)", &l1, &l2, &l3, &l4) )
        return NULL;            

    jumpTo = (int *) l1;
    lenJumpTo = l2;
    return Py_BuildValue("i",  0 );
}

static PyObject* iter(PyObject* self, PyObject* args)
{
    int number;
    PyObject * o1;      
    if (!PyArg_ParseTuple(args, "Oi", &o1,&number) )
        return NULL;    
    
    int i;
    for(i = 0 ; i < totalNumber; i++){
        score[i] = 0;
    }
    
    int node = 0;
    long long unsigned int iloscRund = number * 100;

    
    
    while(iloscRund-- > 0){
    
        if( node >= totalNumber || node < 0 ){
            printf("iteruj.c l89 %d\n",node);
        }
        
        score[node] = score[node] + 1;
        node = nextNode(node);     
    
    }
    
    
    for( i = 0 ; i < totalNumber; i++ )
    {
        PyList_SetItem(o1, (Py_ssize_t) i, PyLong_FromLong( score[i] ) );
    }
    
    return o1;
}

static PyObject* _score(PyObject* self, PyObject* args){
    return Py_BuildValue("i",  (int) score );
}

static PyObject* iter2(PyObject* self, PyObject* args)
{
    srand(0);
    int number;
    if (!PyArg_ParseTuple(args, "ii", &modulo,&number) )
        return NULL;    
    
    int i;
    for(i = 0 ; i < totalNumber; i++){
        score[i] = 0;
    }
    
    int node = 0;
    unsigned int iloscRund = number * 100;

    if(lenJumpTo == 0){
        return Py_BuildValue("i",  0 );
    }
    while(iloscRund-- > 0){
        
        score[node] = score[node] + 1;
        node = nextNode(node);     
    
    }

    return Py_BuildValue("i",  0 );
}

static PyMethodDef HelloMethods[] =
{
     {"putLinks", putLinks, METH_VARARGS, " "},
     {"iter", iter, METH_VARARGS, " "},
     {"iter2", iter2, METH_VARARGS, " "},     
     {"init", _initIter, METH_VARARGS, " "},     
     {"setJump", setJump, METH_VARARGS, " "},          
     {"score", _score, METH_VARARGS, " "},               
     {NULL, NULL, 0, NULL}
};
 
PyMODINIT_FUNC inititeruj(void)
{
     (void) Py_InitModule("iteruj", HelloMethods);
}
